<?php
/**
 *需求模型
 *@author shipanpan
 */
class Cron_Model_Backup_Story extends Application_Model_Story {
	//依赖的模型
	private $_storyBackupLogModel;
	private $_stockTransferApplyModel;
	private $_productPurchaseInfoModel;
	private $_productSalesModel;
	private $_productWarehouseStockModel;
	private $_warehouseProductModel;
	//日志类
	public $log;

	public function __construct() {
		$this->db = $this->db();
		$this->writeDb = $this->db("write_db");
		$this->log = new Log();
	}

	/**
	 * 获取需求需要备货的产品数量
	 * @param  string $goodsSn       sku
	 * @param  string $warehouseCode 商品所在仓库
	 * @param string  $platformWarehouse 商品所属的平台仓
	 * @return [type]                [description]
	 */
	public function getBackupQuantity(string $goodsSn, string $warehouseCode, $platformWarehouse = "", $date) {
		$story = $this->db->getOne($goodsSn, $warehouseCode, $platformWarehouse, $date);
		if ($story) {
			return array_sum($story['a_story_quantity'] + $story['b_story_quantity'] + $story['c_story_quantity']);
		}
		return 0;
	}

	/**
	 * 需求申请调拨
	 * @param  array  $oneStoryRecord 一条需求记录(b_story表的)
	 * @return [type]                 [description]
	 */
	public function applyTransfer(array $oneStoryRecord) {
		$this->_stockTransferApplyModel || $this->_stockTransferApplyModel = new Cron_Model_Backup_StockTransferApply();
		$transferApplyRe = $this->_stockTransferApplyModel->apply($oneStoryRecord);
		if ($transferApplyRe) {
			return true;
		} else {
			return $this->_error($this->_stockTransferApplyModel->getErrorMsg());
		}
	}

	/**
	 * 需求数量限制
	 * (自动计算出的需求a,b,c数量要受商品的最小起定量，装箱数，总备货量等因素的限制而增加或者减少)
	 * @param  [type] $oneStoryRecord 一条需求记录(b_story表的)
	 * @return [type]                 [description]
	 */
	public function storyQuantityLimit($oneStoryRecord) {
		$storyId = $oneStoryRecord['id'];
		$goodsSn = $oneStoryRecord['goods_sn'];
		$warehouse = $oneStoryRecord['warehouse_code'];
		$aStoryQuantity = $oneStoryRecord['a_story_quantity'];
		$bStoryQuantity = $oneStoryRecord['b_story_quantity'];
		$cStoryQuantity = $oneStoryRecord['c_story_quantity'];

		//初始化需求数量变化记录日志
		$this->_storyBackupLogModel = new Cron_Model_Backup_Log($goodsSn, $warehouse);

		$quantityLimitFactor = ['minOrderQuantity', 'packageQuantity', 'backupAmount'];
		$quantityLimitFactorName = ['minOrderQuantity' => '最小起订量限制', 'packageQuantity' => '装箱数限制', 'backupAmount' => '备货总量限制'];
		//初始化 需求c的数量是否因为最小起订量 发生变化的标志
		$backupQuantityHasModifyForMinOrderQuantity = false;

		foreach ($quantityLimitFactor as $factor) {
			$limitFactorMethod = '_' . $factor . 'Limit';
			$factorReturn = $this->$limitFactorMethod($storyId, $goodsSn, $warehouse, $aStoryQuantity, $bStoryQuantity, $cStoryQuantity, $backupQuantityHasModifyForMinOrderQuantity);
			$limitFactorName = $quantityLimitFactorName[$factor] ?? "未知";
			if ($factorReturn === false) {
				$logMsg = '备货数量的' . $limitFactorName . '操作发生错误，错误原因:' . $this->getErrorMsg();
				return $this->_error($logMsg);
			}
			if ($cStoryQuantity === 0) {
				break;
			}
		}
		$this->_storyBackupLogModel->write();
	}

	/**
	 * “产品最小订货量” 对备货数量的限制过滤
	 * @return [type]                          [description]
	 */
	private function _minOrderQuantityLimit($storyId, $goodsSn, $warehouse, int $aStoryQuantity, int $bStoryQuantity, int &$cStoryQuantity, &$backupQuantityHasModifyForMinOrderQuantity) {
		$this->_storyBackupLogModel->log("product_min_order", 0);
		$this->_storyBackupLogModel->log('after_min_order_limit_c_story_quantity', $cStoryQuantity);

		$this->_productPurchaseInfoModel || $this->_productPurchaseInfoModel = new Application_Model_ProductPurchaseInfo();
		$productPurchaseInfo = $this->_productPurchaseInfoModel->getOne($goodsSn);
		if (!$productPurchaseInfo || !$productPurchaseInfo['min_order']) {
			return true;
		}

		//商品的备货数量没有被“最小起订量”规则修改前的值，对比修改后值，用于记录备货数变更日志
		$cStoryStartQuantity = $cStoryQuantity;

		$productMinOrderQuantity = $productPurchaseInfo['min_order'];
		$this->_storyBackupLogModel->log("product_min_order", $productMinOrderQuantity);

		$allStoryBackupQuantity = $aStoryQuantity + $bStoryQuantity + $cStoryQuantity;
		$missingQuantity = $productMinOrderQuantity - $allStoryBackupQuantity;
		if ($allStoryBackupQuantity < $productMinOrderQuantity) {
			//有需求A,总需求加至"最小起订量"，将增加的需求数，增加到需求C。
			if ($aStoryQuantity) {
				$cStoryQuantity += $missingQuantity;
				$backupQuantityHasModifyForMinOrderQuantity = true;
			} elseif (!$aStoryQuantity && $cStoryQuantity) {
				//无需求A，有需求C
				//判断需求B+C数量是否大于等于"最小起订量"的50%；如大于等于，则将总需求加至最小起订量，增加到需求C，如小于则扣除需求C，需求B数量不变
				if (($bStoryQuantity + $cStoryQuantity) >= $productMinOrderQuantity * 0.5) {
					$cStoryQuantity += $missingQuantity;
				} else {
					$cStoryQuantity = 0;
				}
				$backupQuantityHasModifyForMinOrderQuantity = true;
			}
		}

		$this->_storyBackupLogModel->log('after_min_order_limit_c_story_quantity', $cStoryQuantity);
		$cStoryQuantityChange = $cStoryStartQuantity - $cStoryQuantity;
		if ($cStoryQuantityChange) {
			$logStr = ($cStoryQuantityChange < 0 ? '增加' : '减少') . '需求C的数量:' . abs($cStoryQuantityChange);
			$this->updateQuantity($storyId, Application_Model_Story::C_STORY_TYPE, $cStoryQuantity, '最小起订量:' . $productMinOrderQuantity);
			$this->_storyBackupLogModel->log('c_story_quantity_modify_remark', '因不满足最小起订量，' . $logStr);
		}
		return true;
	}

	/**
	 * 整箱数对备货数量的限制过滤
	 * (整箱数是供应商标准装一箱的产品数量，所以此条规则的意义是尽量使备货数量是整箱数的倍数)
	 * @return [type] [description]
	 */
	private function _packageQuantityLimit($storyId, $goodsSn, $warehouse, int $aStoryQuantity, int $bStoryQuantity, int &$cStoryQuantity, $backupQuantityHasModifyForMinOrderQuantity) {
		$this->_storyBackupLogModel->log("after_package_quantity_c_story_quantity", $cStoryQuantity);
		$this->_storyBackupLogModel->log("product_package_quantity", 0);

		$this->_productPurchaseInfoModel || $this->_productPurchaseInfoModel = new Application_Model_ProductPurchaseInfo();
		$productPurchaseInfo = $this->_productPurchaseInfoModel->getOne($goodsSn);
		if (!$productPurchaseInfo || !$productPurchaseInfo['package_num']) {
			return true;
		}

		//商品的备货数量没有被“整箱数”规则修改前的值，对比修改后值，用于记录备货数变更日志
		$cStoryStartQuantity = $cStoryQuantity;
		$packageNum = $productPurchaseInfo['package_num'];
		$this->_storyBackupLogModel->log("product_package_quantity", $packageNum);

		if ($bStoryQuantity == 0 && $cStoryQuantity == 0) {
			return true;
		}

		$allStoryBackupQuantity = $aStoryQuantity + $bStoryQuantity + $cStoryQuantity;
		$remainder = $allStoryBackupQuantity % $packageNum;
		if (!$remainder) {
			return true;
		}

		if ($remainder <= 0.09 * $packageNum) {
			if ($aStoryQuantity) {
				if ($backupQuantityHasModifyForMinOrderQuantity !== false) {
					$greaterThanPackageNum = $cStoryQuantity - $remainder;
					if ($greaterThanPackageNum >= 0) {
						$cStoryQuantity -= $remainder;
					}
				}
			}

		} elseif ($remainder >= 0.9 * $packageNum) {
			if ($aStoryQuantity || $cStoryQuantity) {
				$cStoryQuantity += ($packageNum - $remainder);
			}
		}
		$this->_storyBackupLogModel->log("after_package_quantity_c_story_quantity", $cStoryQuantity);
		$cStoryQuantityChange = $cStoryStartQuantity - $cStoryQuantity;
		if ($cStoryQuantityChange) {
			$logStr = ($cStoryQuantityChange < 0 ? '增加' : '减少') . '需求C的数量:' . abs($cStoryQuantityChange);
			$this->updateQuantity($storyId, Application_Model_Story::C_STORY_TYPE, $cStoryQuantity, '整箱数:' . $packageNum);
			$this->_storyBackupLogModel->log('c_story_quantity_modify_remark', '因不满足整箱数，' . $logStr);
		}
		return true;
	}

	/**
	 * 所有的备货需求(特采备货需求,自动备货需求)总数量限制过滤
	 * @return [type] [description]
	 */
	private function _backupAmountLimit($storyId, $goodsSn, $warehouse, int $aStoryQuantity, int $bStoryQuantity, int &$cStoryQuantity) {
		$this->_productSalesModel || $this->_productSalesModel = new Application_Model_ProductSales();
		$productSalesInfo=$this->_productSalesModel->getOne($goodsSn, $warehouse);

		$fifteenDayBackupSales = $productSalesInfo['sale_15']??0;
		$sevenDayBackupSales = $productSalesInfo['sale_7']??0;
		$sevenDayRealSales = $productSalesInfo['real_sale_7']??0;

		$fifteenDayBackupSalesMean = $fifteenDayBackupSales / 15;
		$sevenDayBackupSalesMean = $sevenDayBackupSales / 7;
		$sevenDayRealSalesMean = $sevenDayRealSales / 7;

		//分母为零
		if ($fifteenDayBackupSalesMean == 0) {
			$rate = 0.5;
		} else {
			$_7DaySalesDivide15DaySales = $sevenDayBackupSalesMean / $fifteenDayBackupSalesMean;
			$rate = $_7DaySalesDivide15DaySales;
			if (min(0.5, $_7DaySalesDivide15DaySales) == $_7DaySalesDivide15DaySales) {
				$rate = 0.5;
			} elseif (max(1.5, $_7DaySalesDivide15DaySales) == $_7DaySalesDivide15DaySales) {
				$rate = 1.5;
			}
		}

		//商品的备货数量没有被“备货总量”规则修改前的值，对比修改后值，用于记录备货数变更日志
		$cStoryStartQuantity = $cStoryQuantity;

		//一个商品备货量总和最大值
		$backupAmountLimit = ((0.4 * $fifteenDayBackupSalesMean + 0.6 * $sevenDayBackupSalesMean) * 2 * $rate * 30) + ($sevenDayRealSalesMean * 3);
		$backupAmountLimit = round($backupAmountLimit, 2);

		//商品现在的可用库存
		$this->_productWarehouseStockModel || $this->_productWarehouseStockModel = new Application_Model_ProductWarehouseStock();
		$productStockInfo = $this->_productWarehouseStockModel->getOne($goodsSn, $warehouse);
		$productStock = 0;
		if ($productStockInfo) {
			$productStock = $productStockInfo['stock_can_allot'] + $productStockInfo['stock_on_way'] + $productStockInfo['stock_order_nums'];
		}

		/**
		 * 商品所有需求可以备货量
		 * (注意:此备货数限制不包含缺货A需求，需求A是缺货的，需求B和需求C是备货，
		 * 首先我要先补全我缺货的数量，再进行备货，而我们只针对备货，做最大量的限制
		 */
		$needBackupQuantity = $backupAmountLimit - $productStock;
		$needBackupQuantity = round($needBackupQuantity, 2);

		//b和c需求产生的备货量
		$b_cStoryBackupQuantity = $cStoryQuantity + $bStoryQuantity;
		$backupQuantityExcess = $b_cStoryBackupQuantity - $needBackupQuantity;

		$this->_warehouseProductModel || $this->_warehouseProductModel = new Application_Model_WarehouseProduct();

		if (($productStock != 0 || $sevenDayBackupSalesMean != 0) || !$this->_warehouseProductModel->isNewProduct($goodsSn, $warehouse)) {
			if ($backupQuantityExcess > 0) {
				if ($needBackupQuantity <= 0) {
					$cStoryQuantity = 0;
				} elseif ($needBackupQuantity > 0) {
					$cStoryQuantity -= min($cStoryQuantity, $backupQuantityExcess);
				}
			}
		}
		$cStoryQuantity = round($cStoryQuantity);

		$this->_storyBackupLogModel->log("product_backup_amount", $backupAmountLimit);
		$this->_storyBackupLogModel->log("after_backup_amount_c_story_quantity", $cStoryQuantity);
		$cStoryQuantityChange = $cStoryStartQuantity - $cStoryQuantity;
		if ($cStoryQuantityChange) {
			$logStr = ($cStoryQuantityChange < 0 ? '增加' : '减少') . '需求C的数量:' . abs($cStoryQuantityChange);
			$this->updateQuantity($storyId, Application_Model_Story::C_STORY_TYPE, $cStoryQuantity, '最大备货量(B+C):' . $b_cStoryBackupQuantity);
			$this->_storyBackupLogModel->log('c_story_quantity_modify_remark', '因备货总量限制，' . $logStr);
		}
		return true;
	}

	/**
	 * 获取备货需求的调拨需求详情
	 * @param  [type] $stroyId [description]
	 * @return [type]          [description]
	 */
	public function getStoryTransferApply(int $stroyId) {
		$storyTransferApplyId = $this->getStoryTransferApplyId($stroyId);
		if ($storyTransferApplyId) {
			return false;
		}

		return $this->db->fetchRow("select *  from b_stock_transfer_log stock_transfer_apply_id = ?", $storyTransferApplyId);
	}

	/**
	 * 获取备货需求申请调拨的记录的id
	 * @param  [type] $stroyId [description]
	 * @return [type]          [description]
	 */
	public function getStoryTransferApplyId(int $stroyId) {
		return $this->db->query("select transfer_apply_id from b_stock_transfer_log story_id = ?", $stroyId)->fetchOne();
	}

	/**
	 * 需求是否要被拦截检查(生成一条缺货需求日志，不产生实际采购需求)
	 * @param  [type] $salesWarehouse  产品销售仓库
	 * @param  [type] $backupWarehouse 产品备货仓库
	 * @return bool true为不拦截，false拦截
	 */
	public function interceptCheck($salesWarehouse, $backupWarehouse) {
		/**
		 * 现在拦截只有仓库绑定检查一项，
		 * 即 只有产品的备货仓库和销售仓库 "同为" 或 "同不为"（分销前海保税仓、前海保税仓、香港仓、分销退税仓)才不会被拦截
		 */
		$checkResult = false;
		if (in_array($salesWarehouse, ['HK', 'FXQHBSWH', 'QHBSWH', 'SZTSWH']) && in_array($backupWarehouse, ['HK', 'FXQHBSWH', 'QHBSWH', 'SZTSWH'])) {
			$checkResult = true;
		}
		if (!in_array($salesWarehouse, ['HK', 'FXQHBSWH', 'QHBSWH', 'SZTSWH']) && !in_array($backupWarehouse, ['HK', 'FXQHBSWH', 'QHBSWH', 'SZTSWH'])) {
			$checkResult = true;
		}
		return $checkResult;
	}

	/**
	 * 生成一条拦截需求记录
	 * @param  [type] $goodsSn        [description]
	 * @param  [type] $storyWarehouse [description]
	 * @param  string $storyType      [description]
	 * @param  int    $storyQuantity  [description]
	 * @param  int    $interceptType  [description]
	 * @return [type]                 [description]
	 */
	public function createInterceptStory($goodsSn, $storyWarehouse, string $storyType, int $storyQuantity, int $interceptType) {
		$productInfo = $this->db->fetchRow("select wh_code from p_product where goods_sn=" . $this->db->quote($goodsSn));
		if (empty($productInfo)) {
			return $this->_error($goodsSn . '产品不存在！');
		}

		if (!self::isValidType($storyType)) {
			return $this->_error('未知的需求类型:' . $storyType);
		}

		$interceptStoryData = [
			'goods_sn' => $goodsSn,
			'story_warehouse' => $storyWarehouse,
			'sales_warehouse' => $productInfo['wh_code'],
			'story_type' => $storyType,
			'quantity' => $storyQuantity,
			'type' => $interceptType,
		];

		return $this->writeDb->insert('b_intercept_story', $interceptStoryData);
	}
}